package org.spbsu.apco.server.scheduler.impl;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spbsu.apco.common.task.core.Ticket;
import org.spbsu.apco.server.scheduler.BaseMinScheduler;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Queue;

/**
 * User: Anton Ovchinnikov
 * Date: 1/10/13
 * Time: 4:45 PM
 */
public class MaxMinScheduler extends BaseMinScheduler {

    private static final Logger LOG = LoggerFactory.getLogger(MaxMinScheduler.class);

    // Implements Max-Min scheduling heuristic as described in:macAdd
    // http://reference.kfupm.edu.sa/content/d/y/dynamic_mapping_of_a_class_of_independen_269040.pdf
    protected void reschedule() {

        clearClientQueues();

        final Collection<Ticket> readyForExecutionTickets = getReadyForExecutionTickets();
        ArrayList<String> clients = new ArrayList<String>(clientTaskQueues.keySet());
        int nTasks = readyForExecutionTickets.size();
        int nClients = clientTaskQueues.size();
        c = new double[nTasks][nClients];

        // initial calculation of r_i and c_i_j
        updateMatrix(readyForExecutionTickets);

        List<Ticket> ticketList = new ArrayList<Ticket>(readyForExecutionTickets);
        while (ticketList.size() > 0) {
            // find the earliest completion time for each task
            int[] minIndexArray = new int[ticketList.size()];
            for (int i = 0; i < ticketList.size(); i++) {
                int minIndex = 0;
                for (int j = 1; j < nClients; j++) {
                    if (c[i][j] < c[i][minIndex]) {
                        minIndex = j;
                    }
                }
                minIndexArray[i] = minIndex;
            }

            // find the task with the maximum earliest completion time
            int maxTaskIndex = 0;
            for (int i = 1; i < minIndexArray.length; i++) {
                if (c[i][minIndexArray[i]] > c[maxTaskIndex][minIndexArray[maxTaskIndex]]) {
                    maxTaskIndex = i;
                }
            }
            // maxTaskIndex - task with the minimum earliest completion time (t_k)
            // minIndexArray[maxTaskIndex] - client that gives the earliest completion time (m_l)

            // assign task t_k to m_l
            int clientIndex = minIndexArray[maxTaskIndex];
            String clientId = clients.get(clientIndex);
            Queue<Ticket> clientTaskQueue = clientTaskQueues.get(clientId);
            clientTaskQueue.add(ticketList.get(maxTaskIndex));
            ticketList.remove(maxTaskIndex);

            // clean one row for debug purposes
            for (int i = 0; i < nClients; i++) {
                c[ticketList.size()][i] = -1;
            }

            // update c_i_l
            updateMatrix(ticketList);
        }
    }
}